4

什么是Docker?

Docker是一种虚拟容器技术,本质上是运行在宿主机上的进程(共享内核),它通过命名空间(Namespaces)实现了资源隔离,并通过CGroups(Control Groups)实现了资源的限额,同时通过写时复制(copy-on-write)实现了高效的文件操作。

Namespaces隔离:文件系统、网络、进程间通信、主机名、进程号、用户权限
CGroups限额:CPU、内存、磁盘 I/O 和带宽
copy-on-write:多个容器之间共享一份镜像

Docker优势:持续集成、版本控制、可移植性、隔离性和安全性

一、docker安装

docker官网:https://docs.docker.com/get-s...

1、安装

安装前先查看docker是否已安装,以及linux内核是否满足要求
# 查看docker
$ docker -v

# 查看内核,内核版本要>3.10
$ uname -r

1.)快速安装

通过下面的快捷命令安装
$ curl -sSL https://get.docker.com/ | sh

2.)手动安装

也可以通过依赖包手动安装(以centos为例)
# 更新yum包
$ sudo yum update

# 安装依赖包
$ sudo yum install -y yum-utils device-mapper-persistent-data lvm2

# 设置国内docker镜像源
$ sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# 查看仓库中所有docker,安装
$ yum list docker-ce --showduplicates | sort -r
$ sudo yum install docker-ce

2、卸载docker

# Ubuntu|Debian
$ sudo apt-get remove docker-ce docker-ce-cli

# centOS
$ sudo yum remove docker docker-common docker-selinux docker-engine container-selinux
卸载Docker默认会保留原Docker的镜像、网络、存储卷等,如需全新安装Docker,需删除目录/var/lib/docker

3、docker服务

# 启动/关闭服务
$ sudo systemctl start docker
$ sudo systemctl stop docker

# 加入随机启动
$ sudo systemctl enable docker

二、docker常用命令

查看docker系统配置信息
$ sudo docker info

1.)sudo权限设置

若每次使用docker命令都需要sudo,比较麻烦,可以通过以下命令添加当前用户到docker附属组:
$ sudo usermod -aG docker 当前用户名  # 需要注销后登录生效

2.)查看容器/镜像

$ docker ps  # 查看本地容器
$ docker images  # 查看本地镜像

# 查看容器详情
$ docker inspect xxx

# 查看容器top进程
$ docker top xxx

3.)下载镜像

创建容器前,可先下好远程镜像,也可以在创建时再下载
# 先查找远程镜像
$ docker search xxx
# 下载
$ docker pull xxx

4.)新建容器

最少参数的创建
# -d:表示后台运行,-it:表示以交互的方式创建,可视化时可通过console打开
$ docker run -d -it --name 容器名 镜像名
更多参数:映射端口、dns、持久存储卷、初始化进程防容器退出
# -p:映射端口,--dns:指定dns解析服务器(/etc/resolv.conf),-v:映射路径(可重复多个),/bin/sh:保持一个进程运行,否则容器会退出
$ docker run -dit -p 宿主端口:容器端口 --dns=8.8.8.8 --name 容器名 -v 宿主路径:容器路径 --restart always 镜像:标签 /bin/sh

docker中安装centos无法使用systemctl命令管理进程,报以下错误:
Failed to get D-Bus connection: Operation not permitted

原因:需要特权才能启动systemd进程,解决方案:
docker run -dit --privileged 其它参数 init

5.)启动/停止容器

$ docker start | restart xxx  # 启动/重启

$ docker stop xxx  # 停止容器
$ docker kill xxx  # 强行终止,关闭进程

6.)进入容器

# /bin/sh或/bin/bash可简写sh或bash
$ docker exec -it xxx /bin/sh

# 自动执行脚本
$ docker exec -it xxx sh -c "chmod +x ./app/entry.sh && ./app/entry.sh"

7.)删除容器/镜像

# 删除容器前需先停止
$ docker stop xxx 
$ docker rm xxx

# 强制删除
$ docker rm xxx -f

# 删除镜像
$ docker rmi xxx  # -f 强制删除

8.)容器/镜像改名

# 容器改名
$ docker rename 原容器名 新容器名

# 镜像改名
$ docker tag 原镜像 新镜像 # 会生成一个新名,镜像id一样
$ docker rmi 原镜像

三、构建镜像

一般可以直接使用官方registry提供的镜像,也可以DIY自己应用场景的镜像,通过手动构建和Dockerfile配置创建两种方式。

1、手动构建镜像

用基础镜像创建一个容器,进入到容器,手动安装好应用和服务,然后用下面的命令将容器创建出镜像:
$ docker commit 容器名 新镜像名

2、Dockerfile构建:

1.)自定义一个alpine镜像

docker中最小的镜像是一个大小为0的空镜像—scratch(也是docker保留关键字)

下面通过最简单的示例,构建出一个很小的alpine镜像(同官方一样只有5M左右):

  • 先下载alpine rootfs内核
$ curl -o alpine.tar.gz https://mirrors.aliyun.com/alpine/v3.10/releases/x86_64/alpine-minirootfs-3.10.2-x86_64.tar.gz
  • 新建Dockerfile,配置如下:
FROM scratch

MAINTAINER hoby<w.hoby@qq.com>

ADD ./alpine.tar.gz /

CMD ["/bin/sh"]
  • 构建镜像,创建容器
# 构建镜像:
$ docker build -t alpine:my .   # "."表示当前目录

# 创建容器
$ docker run -dit --name 容器名 alpine:my

2.)标准的Dockerfile配置

下面是一个基于alpine的node运行环境的实例:
# 基础镜像源
FROM alpine

# 创建者信息
MAINTAINER hoby <w.hoby@qq.com>

# 修复时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
    && echo 'Asia/Shanghai' > /etc/timezone

# RUN命令:构建过程中执行,常用于安装软件包
RUN echo 'nameserver 8.8.8.8' >> /etc/resolv.conf \
    && sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
    && apk add --update-cache bash \
    && apk add bash \
    && apk add nodejs && apk add npm \
    && npm config set registry https://registry.npm.taobao.org

# 指定工作目录,用绝对
WORKDIR /app

# 定义环境变量
ENV NODE_ENV=production

# 从宿主机拷贝www.js和entrypoint.sh到容器
COPY ./app /app

# 与COPY类似,但ADD自带解压功能
#ADD ./x.tar.xz /app

# 配置entrypoint启动脚本
RUN echo -e '#!/bin/bash \nnode /app/www.js' > entrypoint.js \
    && chmod a+x ./entrypoint.sh

# 容器启动后执行的命令,且不可被docker run提供的参数覆盖
ENTRYPOINT ["/bin/sh", "./entrypoint.sh"]

# 容器启动后默认执行的命令,可被docker run后面的参数代替
#CMD ["/bin/sh"]

# 暴露端口
EXPOSE 3000

?示例相关文件:

./app/www.js
// node server
var http = require('http')

http.createServer((req, res) => {
    res.end('hello world!')
}).listen(3000)

console.log('node server is running at 3000...')

构建镜像:

$ docker build -t myimage:latest .  # 镜像名需小写

新建并启动容器:

$ docker run -dit -p 3000:3000 --dns=8.8.8.8 --name 容器名 --restart always myimage:latest

3.)Dockerfile构建总结

a.) 构建时下载不了软件包,说明容器dns不对,需修改/etc/resolv.conf
b.) alpine镜像默认sh终端,需安装bash
c.) 建议一个容器只运行单个应用,多个应用见下文compose部署
d.) Docker镜像构建是分层,将多个RUN指令合并
e.) -v持久化路径时,若宿主机路径是新建的,容器路径内容会被清空
f.) 当ENTRYPOINT与CMD使用exec参数时需双引号
g.) 添加.dockerignore,提高编译速度:
.git/
node_modules/

3、搭建私有镜像库

构建好的镜像可以放在自己的私有registry中
# 本地搭建一个私有registry容器
$ docker run -d -p 5000:5000 --name registry registry:latest

# 给本地镜像打标签
$ docker tag myimage localhost:5000/myimage

# 推送
$ docker push localhost:5000/myimage

# 查看私有镜像数
$ curl localhost:5000/v2/_catalog

四、多应用容器部署

Docker Compose是一个管理多容器应用的工具

1、docker-compose安装

Compose下载地址: https://get.daocloud.io/#inst...
$ curl -L https://get.daocloud.io/docker/compose/releases/download/1.24.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
$ chmod +x /usr/local/bin/docker-compose

# 测试
$ docker-compose -v

2、docker-compose命令

默认需在当前目录有个docker-compose.yml文件
# 查看yml配置
$ docker-compose config

# 查看当前项目多容器状态
$ docker-compose ps

# 启动/重启/停止已存在的容器(对yml配置变化无感)
$ docker-compose start | restart | stop

# 创建并启动容器(容器不存在或yml配置变化时触发)
$ docker-compose up -d  # -d后台运行

# 对于已存在且配置未变化的容器,默认不动作,可以通过参数强制新建重启,但过于浪费
$ docker-compose up -d --force-recreate

# 兼容方案:配置变化时重建,不变则重启(适用于自动化部署)
$ docker-compose stop && docker-compose up -d

# 手动指定配置,多个-f会合并,相同项后面会覆盖前面
$ docker-compose -f a.yml -f b.yml up -d

# 先通过Dockerfile构建镜像,再启动容器
$ docker-compose up -d --build

# 停止并移除容器
$ docker-compose down

3、docker-compose配置

在项目根目录下,新建docker-compose.yml文件

1.)配置示例

以下为nginx+node+mongo+redis联合容器的配置,项目名假设为proj
version: '3'
services:
    web:
        image: nginx
        container_name: proj-web
        restart: always
        ports:
            - 8080:80
        volumes:
            - ./bin/nginx.conf:/etc/nginx/conf.d/default.conf
            - ./web/dist:/app
        command: ['nginx', '-g', 'daemon off;']
        links:
            - server

    server:
        image: mhart/alpine-node
        container_name: proj-server
        restart: always
        ports:
            - 3000:3000
        volumes:
            - ./server:/app
        working_dir: /app
        environment:
            - MONGO_SERVER=mongo
            - MONGO_PORT=27017
            - REDIS_SERVER=redis
            - REDIS_PORT=6379
        command: npm start
        links:
            - mongo
            - redis

    mongo:
        image: mongo
        container_name: proj-mongo
        restart: always
        ports:
            - 27017:27017
        volumes:
            - ./mongo/configdb:/data/configdb
            - ./mongo/db:/data/db
        command: mongod --auth

    redis:
        image: redis
        container_name: proj-redis
        restart: always
        ports:
            - 16379:6379
        volumes:
            - ./redis/data:/data
            - ./bin/redis.conf:/usr/local/etc/redis.conf
        command: redis-server /usr/local/etc/redis.conf

需要注意的:

a.) volumes若映射的是文件,当宿主机修改了,容器需重启,容器内文件才同步
b.) command支持exec和shell两种模式(见上面的web和server)
c.) nginx、pm2等进程需加--no-daemon参数使其在前台运行,以保证容器不退出
d.) npm start需要设置工作目录
e.) links后,在容器可直接把服务名做为一个hostname访问,如下:
# nginx反向代理
proxy_pass http://server:3000/;

# mongo连接
mongodb://mongo:27017/xxxDB

# node容器可先设置环境变量,再动态获取
'mongodb://www:123456@' + process.env.MONGO_SERVER + ':' + process.env.MONGO_PORT + '/xxxDB'

2.)容器部署

在docker-compose.yml同目录下,运行以下命令,创建并启动容器:
$ docker-compose up -d
默认up命令只有当容器不存在或yml文件配置变化时才触发重建重启容器,而当node等web项目本身有更新并不会自动重启,解决方案:
$ docker-compose stop && docker-compose up -d

3.)mysql容器配置

官方mysql容器相对智能,可以自动帮助创建root密码、web数据库、用户/密码、用户权限及初化配置,参考>>
    mysql:
        image: mysql
        container_name: proj-mysql
        restart: always
        ports:
            - 13306:3306
        environment:
            MYSQL_ROOT_PASSWORD: ${dbRootPass}
            MYSQL_USER: ${dbUser}
            MYSQL_PASSWORD: ${dbPass}
            MYSQL_DATABASE: ${dbName}
        volumes:
            - ./bin/my.cnf:/etc/my.cnf
            - ./bin:/docker-entrypoint-initdb.d/
            - ./mysql/db:/var/lib/mysql
        command: --default-authentication-plugin=mysql_native_password
compose配置支持变量替换,只需同目录下配置.env文件:
dbRootPass=root123
dbUser=www
dbPass=123456
dbName=xxxDB
项目下./bin/my.cnf配置:
[mysqld]
user=mysql
default-storage-engine=INNODB
character-set-server=utf8

[client]
default-character-set=utf8

[mysql]
default-character-set=utf8
项目下./bin/init.sql,用来放一些建表等初始化sql,如下:
use xxxDB;

create table xxxTable
(
  id int(11) auto_increment primary key not null,
  name varchar(45),
  update_time datetime
);

需要注意的:

environment:设置的root密码、数据库、数据库权限用户/密码仅在数据库第一次创建时生成,不会随容器的重建或重启而变化
volumes:冒号后面的内容为容器约定路径,不要修改
command:给内置的mysqld命令添加了一个参数,用来解决从mysql5.7版本之后采用了caching_sha2_password验证方式的兼容问题

4.)Dockerfile混合部署

除了使用第三方已有的镜像,也可以通过Dockerfile配置自己的镜像,实时构建后再启动容器
    myapp:
        container_name: proj-myapp
        build: .    # 读取当前目录下Dockerfile文件
部署时需要添加--build参数
$ docker-compose up -d --build

五、可视化容器管理工具

Portainer是一个轻量级的Docker环境UI界面管理系统

1、快速部署

$ docker volume create portainer_data # 在宿主机创建持久化目录
$ docker run -d -p 9000:9000 --name portainer --restart always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer

2、相关配置

1.)交互模式

创建容器时,在高级设置里,Console项记得勾选交互模式,否则无法使用控制台
  • [x] Interactive & TTY (-i -t)

2.)入口命令

在容器高级设置里,command里的shell命令必须单个加引号,如:
Command: 'pm2' 'start' './www.js' '--no-daemon'
Working Dir:  /app

3.)volume添加

portainer中volume默认在/var/lib/docker/volumes下,通过点击bind按钮修改/自定义对应的host路径

4.)查看应用日志

点开Container status下面的logs,在日志界面关掉
Auto-refresh logs自动刷新功能

安静de沉淀
6.5k 声望282 粉丝

忙起来像个狗?,轻松起来像只猫?,没工作闲得像条鱼?